//
//  ImageUtilss.m
//  FunnyReader
//
//  Created by yht on 2025/1/20.
//

#import "ImageUtils.h"
#import <opencv2/opencv.hpp>
#import <opencv2/imgcodecs/ios.h>

@implementation ImageUtils


// Function to convert UIImage to cv::Mat, ios似乎只支持每像素4字节格式
+ (cv::Mat)UIImageToMat:(UIImage *)image {
    CGImageRef imageRef = image.CGImage;
    
    // Get image width and height
    size_t width = CGImageGetWidth(imageRef);
    size_t height = CGImageGetHeight(imageRef);
    
    // Get the color space of the image
    CGColorSpaceRef colorSpace = CGImageGetColorSpace(imageRef);
    
    // Create a suitable color space for OpenCV
    cv::Mat mat;
    mat = cv::Mat(height, width, CV_8UC4);
    
    // Create a context to draw the image into the buffer
    CGContextRef context = CGBitmapContextCreate(mat.data, width, height, 8, mat.step, colorSpace,
                                                  kCGImageAlphaNoneSkipLast);
    if (!context) {
        return cv::Mat();
    }
    
    // Draw the image into the context
    CGRect rect = CGRectMake(0, 0, width, height);
    CGContextDrawImage(context, rect, imageRef);
    CGContextRelease(context);
    
    cv::cvtColor(mat, mat, cv::COLOR_RGBA2BGRA);
    return mat;
}

+ (void)convert4To3ChannelsUsingSplitMerge:(cv::Mat&)inputMat outputMat:(cv::Mat&)outputMat {
    std::vector<cv::Mat> channels;
    // Split the 4 - channel input Mat into individual channels
    cv::split(inputMat, channels);

    // Select the first three channels (R, G, B)
    std::vector<cv::Mat> rgbChannels(channels.begin(), channels.begin() + 3);

    // Merge the three channels into a new 3 - channel Mat
    cv::merge(rgbChannels, outputMat);
}


#pragma mark - cvMatGrayFromUIImage 单通道灰度图
+ (cv::Mat)cvMatGrayFromUIImage:(UIImage *)image
{
  CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);
  CGFloat cols = image.size.width;
  CGFloat rows = image.size.height;
  cv::Mat cvMat(rows, cols, CV_8UC1); // 8 bits per component, 1 channels
  CGContextRef contextRef = CGBitmapContextCreate(cvMat.data,                 // Pointer to data
                                                 cols,                       // Width of bitmap
                                                 rows,                       // Height of bitmap
                                                 8,                          // Bits per component
                                                 cvMat.step[0],              // Bytes per row
                                                 colorSpace,                 // Colorspace
                                                 kCGImageAlphaNoneSkipLast |
                                                 kCGBitmapByteOrderDefault); // Bitmap info flags
  CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image.CGImage);
  CGContextRelease(contextRef);
  return cvMat;
 }


// Function to convert cv::Mat to UIImage
+ (UIImage *)imageWithCVMat:(const cv::Mat &)mat {
    // Check if the Mat is empty
    if (mat.empty()) {
        return nil;
    }
    
    // Convert the Mat to a suitable color space if necessary
    cv::Mat rgbMat;
    if (mat.channels() == 1) {
        // Grayscale image, convert to RGB
        cv::cvtColor(mat, rgbMat, cv::COLOR_GRAY2RGB);
    } else if (mat.channels() == 3) {
        // BGR image, convert to RGB
        cv::cvtColor(mat, rgbMat, cv::COLOR_BGR2RGB);
    } else if (mat.channels() == 4) {
        // BGRA image, convert to RGBA
        cv::cvtColor(mat, rgbMat, cv::COLOR_BGRA2RGBA);
    } else {
        return nil;
    }
    
    // Create a CGImage from the cv::Mat
    NSInteger width = rgbMat.cols;
    NSInteger height = rgbMat.rows;
    NSInteger bytesPerRow = rgbMat.step;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    void *contextData = rgbMat.data;
    
    CGContextRef context = CGBitmapContextCreate(contextData, width, height, 8, bytesPerRow, colorSpace, kCGImageAlphaNoneSkipLast);
    if (!context) {
        CGColorSpaceRelease(colorSpace);
        return nil;
    }
    
    CGImageRef cgImage = CGBitmapContextCreateImage(context);
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    
    if (!cgImage) {
        return nil;
    }
    
    // Create a UIImage from the CGImage
    UIImage *image = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);
    
    return image;
}


// 修正 UIImage 方向为 .up
+ (UIImage*)fixOrientationOfImage:(UIImage*)image {
    if (image.imageOrientation == UIImageOrientationUp) {
        return image;
    }
    UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale);
    CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
    [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
    UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return normalizedImage;
}

@end
